﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Policy;
using System.Security.Cryptography;
using System.IO;
using System.Text.RegularExpressions;
using System.Net;
using System.Drawing;
using DWH.Data;
using log4net;
using System.Threading;

namespace DWH.Utils
{
    public class DWHHelper
    {
        private const string SHORTURL_KEY = "DWH";

        private static ILog logger = LogManager.GetLogger(typeof(DWHHelper));


        public static string[] GetShortUrlId(string url)
        {
            string[] chars = new string[]
            {
                "a","b","c","d","e","f","g","h", 
                "i","j","k","l","m","n","o","p", 
                "q","r","s","t","u","v","w","x", 
                "y","z","0","1","2","3","4","5", 
                "6","7","8","9","A","B","C","D", 
                "E","F","G","H","I","J","K","L", 
                "M","N","O","P","Q","R","S","T", 
                "U","V","W","X","Y","Z" 

            };

            string[] result = new string[4];
            StringBuilder resultBuilder = new StringBuilder();
            string md5code = null;

            using (MD5 alg = MD5.Create())
            {
                byte[] data = alg.ComputeHash(Encoding.UTF8.GetBytes(url));

                StringBuilder sb = new StringBuilder();

                for (int i = 0; i < data.Length; i++)
                {
                    sb.Append(data[i].ToString("x2"));
                }

                md5code = sb.ToString();
            }

            for (int i = 0; i < 4; i++)
            {
                int hexint = 0x3FFFFFFF & Convert.ToInt32("0x" + md5code.Substring(i * 8, 8), 16);

                string outChars = string.Empty;

                for (int j = 0; j < 6; j++)
                {
                    int index = 0x0000003D & hexint;

                    outChars += chars[index];

                    hexint = hexint >> 5;
                }
                resultBuilder.Append(outChars);
                result[i] = outChars;
            }

            //return resultBuilder.ToString();
            return result;
        }

        public static bool PatternMatch(string url, string pattern)
        {
            return Regex.IsMatch(url, pattern, RegexOptions.IgnoreCase);
        }

        public static string FormatUrl(string rootUrl, string shortUrl)
        {
            if (!shortUrl.ToLower().StartsWith("http://"))
            {
                shortUrl = rootUrl + shortUrl;
            }

            shortUrl = shortUrl.Replace("&amp;", "&");//may handle furture xml text entities in the url

            return shortUrl;
        }

        public static List<string> ExtractPatternFromStringContent(string content, string regex, string groupName)
        {
            Regex reg = new Regex(regex, RegexOptions.IgnoreCase);
            MatchCollection mc = reg.Matches(content);

            List<string> results = new List<string>();
            if (mc.Count > 0)
            {
                foreach (Match m in mc)
                {
                    results.Add(m.Groups[groupName].Value);
                }
            }

            return results;
        }

        public static string DownloadWebAttachment(string attUrl, string saveFileName, bool regenerateFileName = false)
        {
            if (File.Exists(saveFileName) && regenerateFileName)
            {
                saveFileName = RegenerateFileName(saveFileName);
            }

            saveFileName = FilterInvalidCharactersForFilePath(saveFileName);

            if (!File.Exists(saveFileName))
            {
                WebClient wc = new WebClient();
                try
                {
                    wc.Headers.Add(HttpRequestHeader.Referer, new Uri(attUrl).Host);
                }
                catch { }
                for (int i = 0; i < 3; i++)
                {
                    try
                    {
                        wc.DownloadFile(attUrl, saveFileName);
                        break;
                    }
                    catch (Exception ex)
                    { }
                }
            }

            return saveFileName;
        }

        public static string RegenerateFileName(string saveFileName)
        {
            if (!File.Exists(saveFileName))
            {
                return saveFileName;
            }

            string dir = Path.GetDirectoryName(saveFileName);
            string fileNameWithoutExt = Path.GetFileNameWithoutExtension(saveFileName);
            string fileExt = Path.GetExtension(saveFileName);
            string newFileName = saveFileName;

            for (int i = 1; i < 100; i++)
            {
                newFileName = String.Format("{0}_{1}{2}", fileNameWithoutExt, i.ToString(), fileExt);

                if (!File.Exists(Path.Combine(dir, newFileName)))
                {
                    break;
                }
            }

            return Path.Combine(dir, newFileName);
        }

        public static string FilterInvalidCharactersForFilePath(string original)
        {
            return original.Replace('?', '_').Replace('*', '_').Replace('&', '_');
        }

        public static void DownloadWebPageImages(string TaskName, string attFolderForThisPage, List<string> images)
        {
            if (null == images || images.Count == 0)
            {
                return;
            }

            foreach (string imgUrl in images)
            {
                DownloadWebPageImage(TaskName, attFolderForThisPage, imgUrl);
            }
        }

        public static void DownloadWebPageImage(string TaskName, string attFolderForThisPage, string imgUrl)
        {
            CreateWebAttachmentFolderIfNotExists(attFolderForThisPage);
            try
            {
                string pictureName = imgUrl.Substring(imgUrl.LastIndexOf('/') + 1);
                pictureName = FilterInvalidCharactersForFilePath(pictureName);
                if (String.IsNullOrEmpty(Path.GetExtension(pictureName)))//handle file names without extension
                {
                    pictureName = pictureName + ".jpg";
                }

                string pictureFilePath = Path.Combine(attFolderForThisPage, pictureName);

                pictureFilePath = DWHHelper.DownloadWebAttachment(imgUrl, pictureFilePath, true);

                logger.InfoFormat("save pic from {0} to {1}", imgUrl, pictureFilePath);

                Image img = Image.FromFile(pictureFilePath);

                if (img.Width < 128 || img.Height < 128)
                {
                    //logger.InfoFormat("picture is too small, delete it {0}", pictureFilePath);
                    //try
                    //{
                    //    img.Dispose();
                    //    File.Delete(pictureFilePath);
                    //}
                    //catch (Exception ex)
                    //{
                    //    logger.ErrorFormat("error occurs when trying to delete small pic {0}", ex.ToString());
                    //}
                }
                else
                {
                    //DWHDBHelper.AddPage(TaskName, imgUrl.GetHashCode(), imgUrl,
                    //    DWHConstants.V_WEB_ATTACHMENT_TITLE_CONTENT_FLAG, pictureFilePath, DateTime.Now);
                    //will update PageAttachment status in upper level
                }

            }
            catch (Exception ex)
            {
                logger.ErrorFormat("error occurs when processing image:{0}, err:{1}", imgUrl, ex.ToString());
            }

        }

        public static string DownloadWebPage(string url)
        {
            WebClient wb = new WebClient();
            return wb.DownloadString(url);
        }

        public static void CreateWebAttachmentFolderIfNotExists(string folder)
        {
            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }
        }

        #region torrent download methods

        //http://www.jandown.com/link.php?ref=pZnJeG3xht
        /*
        POST http://www.jandown.com/fetch.php HTTP/1.1
        Accept: text/html, application/xhtml+xml, * /*
        Referer: http://www.jandown.com/link.php?ref=pZnJeG3xht
        Accept-Language: en-US
        User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
        Content-Type: multipart/form-data; boundary=---------------------------7dc18f35c1f7e
        Accept-Encoding: gzip, deflate
        Host: www.jandown.com
        Content-Length: 149
        Connection: Keep-Alive
        Pragma: no-cache
        Cookie: __utmc=75495433; __utma=75495433.888100250.1334144374.1343749072.1344006155.17; __utmz=75495433.1344006155.17.16.utmcsr=70.85.48.252|utmccn=(referral)|utmcmd=referral|utmcct=/bt/htm_data/16/1208/540018.html

        -----------------------------7dc18f35c1f7e
        Content-Disposition: form-data; name="code"

        pZnJeG3xht
        -----------------------------7dc18f35c1f7e--
        */
        public static void DownloadTorrentJandown(string torrentUrl, string torrentSaveFolder)
        {
            string torrentCode = torrentUrl.Substring(torrentUrl.LastIndexOf("ref=") + 4);
            string torrentDownloadUrl = "http://www.jandown.com/fetch.php";
            string torrentSaveFile = Path.Combine(torrentSaveFolder, torrentCode + ".torrent");

            CreateWebAttachmentFolderIfNotExists(torrentSaveFolder);

            if (File.Exists(torrentSaveFile))
            {
                torrentSaveFile = RegenerateFileName(torrentSaveFile);
            }

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(torrentDownloadUrl);
            req.Referer = torrentUrl;
            req.Host = "www.jandown.com";
            req.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
            req.ContentType = "multipart/form-data; boundary=---------------------------7dc282174b0599";
            req.Method = "POST";

            req.Headers.Add("Pragma", "no-cache");

            string requestContentString = "-----------------------------7dc282174b0599\n"
                + "Content-Disposition: form-data; name=\"code\"\n\n"
                + torrentCode + "\n"
                + "-----------------------------7dc282174b0599--";
            byte[] requestContentBytes = Encoding.UTF8.GetBytes(requestContentString);
            req.GetRequestStream().Write(requestContentBytes, 0, requestContentBytes.Length);

            WebResponse res = req.GetResponse();
            Stream resStream = res.GetResponseStream();

            FileStream writer = new FileStream(torrentSaveFile, FileMode.CreateNew, FileAccess.Write);
            byte[] buff = new byte[512];
            int c = 0;
            while ((c = resStream.Read(buff, 0, buff.Length)) > 0)
            {
                writer.Write(buff, 0, c);
            }
            writer.Close();
        }

        //http://www1.uhopefind.info/link.php?ref=C99P6sWhz6
        /*
         POST http://www1.uhopefind.info/down.php HTTP/1.1
        Accept: text/html, application/xhtml+xml, * /*
        Referer: http://www1.uhopefind.info/link.php?ref=C99P6sWhz6
        Accept-Language: en-US
        User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
        Content-Type: multipart/form-data; boundary=---------------------------7dc2fe1ff171c
        Accept-Encoding: gzip, deflate
        Host: www1.uhopefind.info
        Content-Length: 251
        Connection: Keep-Alive
        Pragma: no-cache
        Cookie: AJSTAT_ok_times=3

        -----------------------------7dc2fe1ff171c
        Content-Disposition: form-data; name="ref"

        C99P6sWhz6
        -----------------------------7dc2fe1ff171c
        Content-Disposition: form-data; name="submit"

        下载文件
        -----------------------------7dc2fe1ff171c--
         */
        public static void DownloadTorrentUhopefind(string torrentUrl, string torrentSaveFolder)
        {
            string torrentCode = torrentUrl.Substring(torrentUrl.LastIndexOf("ref=") + 4);
            string torrentDownloadUrl = "http://www1.uhopefind.info/down.php";
            string torrentSaveFile = Path.Combine(torrentSaveFolder, torrentCode + ".torrent");

            CreateWebAttachmentFolderIfNotExists(torrentSaveFolder);

            if (File.Exists(torrentSaveFile))
            {
                torrentSaveFile = RegenerateFileName(torrentSaveFile);
            }

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(torrentDownloadUrl);

            //to avoid (417) Expectation Failed error when receiving response
            //http://blog.csdn.net/vince6799/article/details/6763472
            ServicePointManager.Expect100Continue = false;
            req.Referer = torrentUrl;
            req.Host = "www1.uhopefind.info";
            req.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
            req.ContentType = "multipart/form-data; boundary=---------------------------7dc2fe1ff171c";
            req.Method = "POST";

            req.Headers.Add("Pragma", "no-cache");

            string requestContentString = "-----------------------------7dc2fe1ff171c\n"
                + "Content-Disposition: form-data; name=\"ref\"\n\n"
                + torrentCode + "\n"
                + "-----------------------------7dc2fe1ff171c\n"
                + "Content-Disposition: form-data; name=\"submit\"\n\n"
                + "下载文件\n"
                + "-----------------------------7dc2fe1ff171c--";
            byte[] requestContentBytes = Encoding.GetEncoding("gb2312").GetBytes(requestContentString);
            req.GetRequestStream().Write(requestContentBytes, 0, requestContentBytes.Length);

            WebResponse res = req.GetResponse();
            Stream resStream = res.GetResponseStream();

            FileStream writer = new FileStream(torrentSaveFile, FileMode.CreateNew, FileAccess.Write);
            byte[] buff = new byte[512];
            int c = 0;
            while ((c = resStream.Read(buff, 0, buff.Length)) > 0)
            {
                writer.Write(buff, 0, c);
            }
            writer.Close();
        }

        /*
         POST http://bfxzw.com/download.php HTTP/1.1
            Accept: text/html, application/xhtml+xml, * /*
            Referer: http://bfxzw.com/link.php?ref=FkpQW5gPcR
            Accept-Language: en-US
            User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
            Content-Type: multipart/form-data; boundary=---------------------------7dc12d1321040
            Accept-Encoding: gzip, deflate
            Host: bfxzw.com
            Content-Length: 251
            Connection: Keep-Alive
            Pragma: no-cache
            Cookie: AJSTAT_ok_pages=1; AJSTAT_ok_times=1

            -----------------------------7dc12d1321040
            Content-Disposition: form-data; name="ref"

            FkpQW5gPcR
            -----------------------------7dc12d1321040
            Content-Disposition: form-data; name="submit"

            DownLoad
            -----------------------------7dc12d1321040--
         */
        public static void DownloadTorrentCLBfxzw(string torrentUrl, string torrentSaveFolder)
        {
            string torrentCode = torrentUrl.Substring(torrentUrl.LastIndexOf("ref=") + 4);
            string torrentDownloadUrl = "http://www.bfxzw.com/download.php";
            string torrentSaveFile = Path.Combine(torrentSaveFolder, torrentCode + ".torrent");

            CreateWebAttachmentFolderIfNotExists(torrentSaveFolder);

            if (File.Exists(torrentSaveFile))
            {
                torrentSaveFile = RegenerateFileName(torrentSaveFile);
            }

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(torrentDownloadUrl);
            ServicePointManager.Expect100Continue = false;

            req.Accept = "text/html, application/xhtml+xml, */*";
            req.Referer = torrentUrl;
            req.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US");
            req.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
            req.ContentType = "multipart/form-data; boundary=---------------------------7dc12d1321040";
            req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
            req.Host = "www.bfxzw.com";
            //req.Connection = "Keep-Alive";
            //req.Headers.Add(HttpRequestHeader.Pragma, "no-cache");
            req.Headers.Add(HttpRequestHeader.Cookie, "AJSTAT_ok_times=1");

            req.Method = "POST";

            req.Headers.Add("Pragma", "no-cache");

            string requestContentString = "-----------------------------7dc12d1321040\n"
                + "Content-Disposition: form-data; name=\"ref\"\n\n"
                + torrentCode + "\n"
                + "-----------------------------7dc12d1321040\n"
                + "Content-Disposition: form-data; name=\"submit\"\n\n"
                + "DownLoad" + "\n"
                + "-----------------------------7dc12d1321040--";
            byte[] requestContentBytes = Encoding.UTF8.GetBytes(requestContentString);
            req.GetRequestStream().Write(requestContentBytes, 0, requestContentBytes.Length);

            WebResponse res = req.GetResponse();
            Stream resStream = res.GetResponseStream();

            FileStream writer = new FileStream(torrentSaveFile, FileMode.CreateNew, FileAccess.Write);
            byte[] buff = new byte[512];
            int c = 0;
            while ((c = resStream.Read(buff, 0, buff.Length)) > 0)
            {
                writer.Write(buff, 0, c);
            }
            writer.Close();
        }

        /*
         POST http://www.rmdown.com/download.php HTTP/1.1
        Accept: text/html, application/xhtml+xml, * /*
        Referer: http://www.rmdown.com/link.php?hash=12211d60cac03a09e984c3e71c9eb5304a587d7f2e2
        Accept-Language: en-US
        User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
        Content-Type: multipart/form-data; boundary=---------------------------7dc168e129a
        Accept-Encoding: gzip, deflate
        Host: www.rmdown.com
        Content-Length: 385
        Connection: Keep-Alive
        Pragma: no-cache

        -----------------------------7dc168e129a
        Content-Disposition: form-data; name="ref"

        12211d60cac03a09e984c3e71c9eb5304a587d7f2e2
        -----------------------------7dc168e129a
        Content-Disposition: form-data; name="reff"

        MTM0NTQ4MzA1Mw==
        -----------------------------7dc168e129a
        Content-Disposition: form-data; name="submit"

        download
        -----------------------------7dc168e129a--

         */
        public static void DownloadTorrentCLRmdown(string torrentUrl, string torrentSaveFolder)
        {
            string torrentCode = torrentUrl.Substring(torrentUrl.LastIndexOf("hash=") + 4);
            string torrentDownloadUrl = "http://www.rmdown.com/download.php";
            string torrentSaveFile = Path.Combine(torrentSaveFolder, torrentCode + ".torrent");

            CreateWebAttachmentFolderIfNotExists(torrentSaveFolder);

            if (File.Exists(torrentSaveFile))
            {
                torrentSaveFile = RegenerateFileName(torrentSaveFile);
            }

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(torrentDownloadUrl);
            //ServicePointManager.Expect100Continue = false;

            //req.Accept = "text/html, application/xhtml+xml, */*";
            req.Referer = torrentUrl;
            req.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US");
            req.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
            req.ContentType = "multipart/form-data; boundary=---------------------------7dc211218e129a";
            req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
            req.Host = "www.rmdown.com";
            //req.Connection = "Keep-Alive";
            //req.Headers.Add(HttpRequestHeader.Pragma, "no-cache");

            req.Method = "POST";

            req.Headers.Add("Pragma", "no-cache");

            string pageContent = DWHHelper.DownloadWebPage(torrentUrl);
            string reffValue = Regex.Match(pageContent, "NAME=\"reff\"\\svalue=\"(?<reff>[A-Za-z0-9]*=*)\"").Groups["reff"].Value;//<INPUT TYPE="hidden" NAME="reff" value="MTM0NTQ4MzA1Mw==">

            string requestContentString = "---------------------------7dc211218e129a\n"
                + "Content-Disposition: form-data; name=\"ref\"\n\n"
                + torrentCode + "\n"
                + "---------------------------7dc211218e129a\n"
                + "Content-Disposition: form-data; name=\"reff\"\n\n"
                + reffValue + "\n"
                + "Content-Disposition: form-data; name=\"submit\"\n\n"
                + "download" + "\n"
                + "---------------------------7dc211218e129a--";
            byte[] requestContentBytes = Encoding.UTF8.GetBytes(requestContentString);
            req.GetRequestStream().Write(requestContentBytes, 0, requestContentBytes.Length);

            WebResponse res = req.GetResponse();
            Stream resStream = res.GetResponseStream();

            FileStream writer = new FileStream(torrentSaveFile, FileMode.CreateNew, FileAccess.Write);
            byte[] buff = new byte[512];
            int c = 0;
            while ((c = resStream.Read(buff, 0, buff.Length)) > 0)
            {
                writer.Write(buff, 0, c);
            }
            writer.Close();
        }


        #endregion

        public static void SimulateUserClickInterval(int maxSleepSeconds, bool random = true)
        {
            if (random)
            {
                Thread.Sleep(new Random().Next(maxSleepSeconds) * 1000); //sleep for a while to simulate user visit   
            }
            else
            {
                Thread.Sleep(maxSleepSeconds * 1000);
            }
        }
    }
}
